错误监控
# 错误监控
如何监测 js 错误?
如何保证产品质量?
[TOC]
# 一、前端错误的分类
# 2.1 即时运行错误(代码错误)
# 2.2 资源加载错误
# 二、每种错误的捕获方式
# 2.1 即时运行错误的捕获方式
# 2.1.1 try - catch
这种方式要部署在代码中。
# 2.1.2 window.onerror
这个函数是全局的。
window.onerror = function(msg, url, row, col, error) { ... }
参数解释:
- msg为异常基本信息
- source为发生异常Javascript文件的url
- row为发生错误的行号
window.onerror
是属于DOM0的写法,我们也可以用DOM2的写法:window.addEventListener("error", fn);
也可以。
# 2.1.2.1 捕获跨域的JS运行错误
window.onerror
默认无法捕获跨域的js运行错误。捕获出来的信息,基本属于无效信息。
比如说,我们的代码想引入B网站的b.js
文件,怎么捕获它的异常呢?
解决办法:在window.onerror基础之上,做如下操作:
- 服务端:设置js资源响应头Acess-Control-Allow-Origin:*
在b.js
文件里,加入如下 response header,表示允许跨域:(或者直接给静态资源b.js
加这个 response header)
Access-Control-Allow-Origin: *
- 客户端:在script标签添加crossorigin属性。
引入第三方的文件b.js
时,在<script>
标签中增加crossorigin
属性。
参考链接:
- window.onerror的总结 (opens new window)
- 前端代码异常日志收集与监控 (opens new window)
- 捕获页面中全局Javascript异常 (opens new window)
问题延伸2:
只靠window.onerror是不够的,因为我们无法获取文件名是什么,不知道哪里出了错误。解决办法:把堆栈信息作为msg打印出来,堆栈里很详细。
# 2.2 资源加载错误的捕获方式
window.onerror只能捕获即时运行错误,无法捕获资源加载错误。原理是:资源加载错误,并不会向上冒泡,object.onerror捕获后就会终止(不会冒泡给window),所以window.onerror并不能捕获资源加载错误。
# 2.2.1 object.onerror
img标签、script标签等节点都可以添加onerror事件,用来捕获资源加载的错误。
# 2.2.2 performance.getEntries
可以获取所有已加载资源的加载时长,通过这种方式,可以间接的拿到没有加载的资源错误。
举例:
浏览器打开一个网站,在Console控制台下,输入:
performance.getEntries().forEach(function(item){console.log(item.name)})
或者输入:
performance.getEntries().forEach(item=>{console.log(item.name)})
上面这个api,返回的是数组。打印出来的资源就是已经成功加载的资源。
再输入document.getElementsByTagName('img')
,就会显示出所有需要加载的的img集合。
于是,document.getElementsByTagName('img')
获取的资源数组减去通过performance.getEntries()
获取的资源数组,剩下的就是没有成功加载的,间接捕获到资源加载错误。
# 2.2.3 Error事件捕获
资源源加载错误,虽然会阻止冒泡,但是不会阻止捕获。我们可以在捕获阶段绑定error事件。
参考链接:
# 三、错误上报的两种方式
# 3.1 采用Ajax通信的方式上报
此方式虽然可以上报错误,但是我们并不采用这种方式。
# 3.2 利用Image对象上报
推荐,网站的监控体系都是采用的这种方式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
//通过Image对象进行错误上报
(new Image()).src = 'http://smyhvae.com/myPath?badjs=msg';
// myPath表示上报的路径(我要上报到哪里去)。后面的内容是自己加的参数。
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
打开浏览器,效果如下:
上图中,红色那一栏表明,我的请求已经发出去了。点进去看看:
这种方式,不需要借助第三方的库,一行代码即可搞定。